﻿using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sasa.QualityTools.CodeAnalysis.Core.Utilities;
using Sasa.QualityTools.CodeAnalysis.Core.Models;
using System.IO;
using System.Reflection;

namespace Sasa.QualityTools.CodeAnalysis.Core.Tests.Unit.Utilities
{
    [TestFixture]
    public class MissingAssemblyResolverTest
    {
        private static readonly string CachePath = Path.Combine(Environment.CurrentDirectory, "Resources", "Utilities", "MissingAssemblyResolver", "Cache");


        [SetUp]
        public void SetUp()
        {
            if (Directory.Exists(CachePath))
            {
                Directory.Delete(CachePath, true);
            }
            Directory.CreateDirectory(CachePath);
        }

        [TearDown]
        public void TearDown()
        {
            Directory.Delete(CachePath, true);
        }

        [Test]
        public void ConstructorShouldIgnoreInvalidAssemblyPath()
        {
            var assembly = GetType().Assembly;
            var testee = new MissingAssemblyResolver(CachePath, new List<string> { assembly.Location, "abc" });

            var field = testee.GetType().GetField("assemblyPaths", BindingFlags.Instance | BindingFlags.NonPublic);
            var assemblyPaths = field.GetValue(testee) as Dictionary<string, string>;
            Assert.AreEqual(1, assemblyPaths.Count);
            Assert.AreEqual(assembly.Location, assemblyPaths[assembly.FullName]);
        }

        [Test]
        public void ResolveShouldThrowExceptionWhenAnalysisErrorsDoNotContainAssemblyReferenceError()
        {
            var assemblyPaths = new List<string>();
            var testee = new MissingAssemblyResolver(CachePath, assemblyPaths);
            var errors = new List<CodeAnalysisError>();
            Assert.Throws<MissingAssemblyResolutionException>(() => testee.Resolve(errors));
        }

        [TestCase("CA0058")]
        [TestCase("CA0060")]
        public void ResovleShouldThrowExceptionWhenErrorMessageDoesNotContainAssemblyName(string id)
        {
            var assemblyPaths = new List<string>();
            var testee = new MissingAssemblyResolver(CachePath, assemblyPaths);
            var errors = new List<CodeAnalysisError>();
            errors.Add(new CodeAnalysisError { Id = id, Message = "" });
            Assert.Throws<MissingAssemblyResolutionException>(() => testee.Resolve(new List<CodeAnalysisError>(errors)));
        }

        [TestCase("CA0058")]
        [TestCase("CA0060")]
        public void ResovleShouldThrowExceptionWhenAssemblyNameIsNotContainedReferencingAssemblies(string id)
        {
            var assemblyPaths = new List<string>();
            var testee = new MissingAssemblyResolver(CachePath, assemblyPaths);
            var errors = new List<CodeAnalysisError>();
            errors.Add(new CodeAnalysisError { Id = id, Message = "'" + GetType().Assembly.FullName + "'" });
            Assert.Throws<MissingAssemblyResolutionException>(() => testee.Resolve(new List<CodeAnalysisError>(errors)));
        }

        [TestCase("CA0058")]
        [TestCase("CA0060")]
        public void ResovleShouldThrowExceptionWhenAssemblyIsAlreadyCached(string id)
        {
            var assemblyPaths = new List<string> { GetType().Assembly.Location };
            var testee = new MissingAssemblyResolver(CachePath, assemblyPaths);
            var errors = new List<CodeAnalysisError>();
            errors.Add(new CodeAnalysisError { Id = id, Message = "'" + GetType().Assembly.FullName + "'" });
            errors.Add(new CodeAnalysisError { Id = id, Message = "'" + GetType().Assembly.FullName + "'" });
            Assert.Throws<MissingAssemblyResolutionException>(() => testee.Resolve(new List<CodeAnalysisError>(errors)));
        }

        [TestCase("CA0058")]
        [TestCase("CA0060")]
        public void ResolveShouldCopyAssemblyThatIsSpecifiedInTheErrorMessage(string id)
        {
            var assembly = GetType().Assembly;
            var assemblyPaths = new List<string>();
            var testee = new MissingAssemblyResolver(CachePath, new string[] { assembly.Location });
            var errors = new List<CodeAnalysisError>();
            errors.Add(new CodeAnalysisError { Id = id, Message = "'" + assembly.FullName + "'" });

            testee.Resolve(errors);

            var assemblyName = assembly.GetName();
            var fileName = "Sasa.QualityTools.CodeAnalysis.Core.Tests.Unit.dll";
            Assert.IsTrue(File.Exists(Path.Combine(CachePath, fileName)));
        }
    }
}
